package com.liuyang.demo.redis;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;

/**
 * @author yzw
 * @date 2019/07/17 18:19
 */
@Slf4j
@Configuration
@EnableCaching
public class RedisConfig extends BaseRedisConfig {

    /**
     * 在使用@Cacheable时，如果不指定key，则使用这个默认的key生成器生成的key
     *
     * @return
     */
    @Override
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName()).append(".");
            sb.append(method.getName()).append("(");
            if (params.length > 0) {
                sb.append(StringUtils.join(params, ","));
            }
            sb.append(")");
            return sb.toString();
        };
    }

    /**
     * 声明缓存管理器
     * <p>
     * 1. entryTtl: 定义默认的cache time-to-live.
     * 2. disableCachingNullValues: 禁止缓存Null对象. 视需求而定.
     * 3. computePrefixWith: 此处定义了cache key的前缀, 避免公司不同项目之间的key名称冲突.
     * 4. serializeKeysWith, serializeValuesWith: 定义key和value的序列化协议, 同时的hash key和hash value也被定义.
     */
    @Override
    @Bean
    @Primary
    public CacheManager cacheManager() {
        // 缓存配置
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .computePrefixWith(cacheName -> "Consts.REDIS_KEY_PRE".concat(":").concat(cacheName).concat(":"))
                .serializeKeysWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer()))
                .serializeValuesWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofHours(1));

        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(cacheConfiguration).transactionAware().build();
        cacheManager.afterPropertiesSet();
        log.info("RedisCacheManager config success");

        return cacheManager;
    }
}
